#include "EntityManagement.h"
EntityManagement::EntityManagement()
{
    ym::Json *col = Data::getInstance()->getData("config")->get("collisionquadtree");
    if (col->get("enable")->getBool())
    {
        ym::Json::Array array = col->get("size")->getArray();
        Vector2 size(array.at(0)->getDouble(), array.at(1)->getDouble());
        int objmax = col->get("objectsmax")->getInt();
        int deepmax = col->get("deepmax")->getInt();
        collisionManagement.generateQuadTree(CollisionEntityRectangle(size), objmax, deepmax);
        SDL_Log("Qua");
    }
    data = Data::getInstance();
}

EntityManagement::~EntityManagement()
{
    for (auto it = entities_list.begin(); it != entities_list.end();)
    {
        delete (*it);
        it = entities_list.erase(it);
    }
    for (auto it = bullets_list.begin(); it != bullets_list.end();)
    {
        delete (*it);
        it = bullets_list.erase(it);
    }
    for (auto it = orders_map.begin(); it != orders_map.end();)
    {
        std::queue<UnitOrder *> *que = it->second;
        while (!que->empty())
        {
            UnitOrder *order = que->front();
            que->pop();
            delete order;
        }
        delete que;
    }
}

void EntityManagement::destroyEntity(Entity *entity)
{
    if (entity == nullptr)
    {
        return;
    }
    entity->exit();
    if (entity->getCollisionEntity() != nullptr)
    {
        entity->getCollisionEntity()->setParent();
    }
    auto it = orders_map.find(entity);
    if (it != orders_map.end())
    {
        delete it->second;
        orders_map.erase(it);
    }
    entity->hover = false;
    entity->isSelected = false;
}

void EntityManagement::destroyBullet(Bullet *bullet)
{
    if (bullet == nullptr)
    {
        return;
    }
    bullet->exit();
    if (bullet->getCollisionEntity() != nullptr)
    {
        bullet->getCollisionEntity()->setParent();
    }
}

Entity *EntityManagement::createEntity(ym::Json *data, Vector2 position, real facing)
{
    Entity *ent = new Entity();
    ent->setPosition(position);
    ent->setFacing(facing);
    entities_list.push_back(ent);
    return ent;
}

Entity *EntityManagement::createShip(ym::Json *data, Vector2 position, int owerPlayerID, real facing)
{
    Ship *ship = new Ship();
    ship->setFacing(facing);
    ship->setOwnerID(owerPlayerID);
    strcpy_s(ship->name, sizeof(ship->name), data->get("name")->getString().c_str());
    ship->hp = data->get("hp")->getInt();
    ship->maxhp = data->get("hp")->getInt();
    ship->setAngleVelocity(data->get("anglevelocity")->getDouble());
    ship->setVelocity(data->get("minvelocity")->getDouble());
    ship->setMinVelocity(ship->getMinVelocity());
    ship->setMaxVelocity(data->get("maxvelocity")->getDouble());
    ship->setAcceleration(data->get("acceleration")->getDouble());
    ym::Json *images = data->get("images");
    Resource *resource = Resource::getInstance();
    ship->setRenderSize(Vector2(images->get("scalewidth")->getInt(), images->get("scalewidth")->getInt()));
    ship->selectable = data->get("selectable")->getBool();
    ship->selectedRange = data->get("selectedrange")->getInt();
    ship->selectedSize = data->get("selectedsize")->getInt();
    ship->setImage(resource->getImage(images->get("imagepath")->getString()));
    ship->allowMoveFacingDifference = data->get("allowmovefacingdifference")->getDouble();
    entities_list.push_back(ship);
    std::string type = data->get("type")->getString();
    ym::Json::Object collision = data->get("collision")->getObject();
    std::string shape = collision.at("shape")->getString();
    if (shape.compare("circle") == 0)
    {
        CollisionEntityCircle *cir = new CollisionEntityCircle(collision.at("size")->getDouble(), ship);
        ship->setCollisionEntity(cir);
        ship->getCollisionEntity()->updatePosition(position);
    }
    if (type.compare("building") == 0)
    {
        std::string buildingtype = data->get("buildingtype")->getString();
        if (buildingtype.compare("base") == 0)
        {
            ship->isBase = true;
        }
        ship->getCollisionEntity()->setFixed(true);
        position.x = ((int)(position.x / collisionManagement.getMesh()->cellSize)) * collisionManagement.getMesh()->cellSize;
        position.y = ((int)(position.y / collisionManagement.getMesh()->cellSize)) * collisionManagement.getMesh()->cellSize;
        ship->getCollisionEntity()->updatePosition(position);
    }
    collisionManagement.add(ship->getCollisionEntity());
    ship->setPosition(position);

    // slots
    if (data->hasKey("slots"))
    {
        ym::Json::Array parts_arr = data->get("slots")->getArray();
        for (auto it = parts_arr.begin(); it != parts_arr.end(); ++it)
        {
            ym::Json::Object obj = (*it)->getObject();
            std::string type = obj.at("type")->getString();
            int layer = obj.at("layer")->getInt();
            int slot = obj.at("slot")->getInt();
            ym::Json::Array arr = obj.at("position")->getArray();
            Vector2 pos(arr.at(0)->getDouble(), arr.at(1)->getDouble());
            ship->slots[slot].position = pos;
            ship->slots[slot].layer = layer;
            auto it1 = obj.find("flip");
            if (it1 != obj.end())
            {
                std::string flip = (*it1).second->getString();
                if (flip.compare("horizontal") == 0)
                {
                    ship->slots[slot].flip = Flip::HORIZONTAL;
                }
                else if (flip.compare("vertical") == 0)
                {
                    ship->slots[slot].flip = Flip::VERTICAL;
                }
                else
                {
                    ship->slots[slot].flip = Flip::NONE;
                }
            }
            else
            {
                ship->slots[slot].flip = Flip::NONE;
            }
        }
    }
    for (int i = 0; i < sizeof(ship->slots) / sizeof(ship->slots[0]); ++i)
    {
        ship->slots[i].part = nullptr;
    }

    return ship;
}

Entity *EntityManagement::createGold(Vector2 pos)
{
    ym::Json *data = Data::getInstance()->getData("mine");
    Ship *ship = new Ship();
    ship->setPosition(pos);
    ship->setOwnerID(13);
    strcpy_s(ship->name, sizeof(ship->name), data->get("name")->getString().c_str());
    ym::Json *images = data->get("images");
    Resource *resource = Resource::getInstance();
    ship->setRenderSize(Vector2(images->get("scalewidth")->getInt(), images->get("scalewidth")->getInt()));
    ship->selectable = data->get("selectable")->getBool();
    ship->selectedRange = data->get("selectedrange")->getInt();
    ship->selectedSize = data->get("selectedsize")->getInt();
    ship->setImage(resource->getImage(images->get("imagepath")->getString()));
    ship->allowMoveFacingDifference = data->get("allowmovefacingdifference")->getDouble();
    ship->hp = 50;
    ship->maxhp = 50;
    entities_list.push_back(ship);
    // ship->animation = createAnimation(Data::getInstance()->getData(data->get("animation")->getString().c_str()));
    std::string type = data->get("type")->getString();
    ym::Json::Object collision = data->get("collision")->getObject();
    std::string shape = collision.at("shape")->getString();
    // ((Animation *)ship->animation)->start();
    if (shape.compare("circle") == 0)
    {
        CollisionEntityCircle *cir = new CollisionEntityCircle(collision.at("size")->getDouble(), ship);
        ship->setCollisionEntity(cir);
        ship->getCollisionEntity()->updatePosition(pos);
    }
    if (type.compare("building") == 0)
    {
        std::string buildingtype = data->get("buildingtype")->getString();
        if (buildingtype.compare("base") == 0)
        {
            ship->isBase = true;
        }
        ship->getCollisionEntity()->setFixed(true);
    }
    collisionManagement.add(ship->getCollisionEntity());
    return ship;
}

Bullet *EntityManagement::createBullet(Slot *slot, Entity *owner, Entity *target)
{
    Part *part = slot->part;
    Bullet *bullet = new Bullet();
    Bullet *data = part->bullet;
    bullet->setVelocity(data->getMinVelocity());
    bullet->setMinVelocity(data->getMinVelocity());
    bullet->setMaxVelocity(data->getMaxVelocity());
    bullet->setAcceleration(data->getAcceleration());
    bullet->setAngleVelocity(data->getAngleVelocity());
    bullet->setRenderSize(data->getRenderSize());
    bullet->setImage(data->getImage());
    bullet->setOwner(owner);
    bullet->setTarget(target);
    real length = slot->position.length();
    real rad = owner->getFacing() * PI / 180 - so_atan2(slot->position.y, slot->position.x) + PI / 2;
    Vector2 offsetPos = Vector2(owner->getPosition().x + length * so_cos(rad), owner->getPosition().y + length * so_sin(rad));
    rad = slot->part->getFacing() * PI / 180 - so_atan2(slot->part->bulletOffset.y, slot->part->bulletOffset.x) + PI / 2;
    length = slot->part->bulletOffset.length();
    offsetPos = Vector2(offsetPos.x + length * so_cos(rad), offsetPos.y + length * so_sin(rad));
    bullet->setPosition(offsetPos);
    bullet->setAliveTime(data->getAliveTime());
    bullet->setAttack(part->attack);
    bullet->setErrorAngle(data->getErrorAngle());
    bullet->birthEffect = data->birthEffect;
    bullet->deathEffect = data->deathEffect;
    if (bullet->birthEffect.size() > 0)
    {
        effectManagement.createEffect(Data::getInstance()->getData(bullet->birthEffect.c_str()), bullet->getPosition(), bullet->getFacing(), 0);
    }
    CollisionEntityCircle *cir = dynamic_cast<CollisionEntityCircle *>(data->getCollisionEntity());
    if (cir != nullptr)
    {
        CollisionEntityCircle *cir2 = new CollisionEntityCircle(cir->getRadius(), bullet);
        bullet->setCollisionEntity(cir2);
        cir2->updatePosition(bullet->getPosition());
        // collisionManagement.add(cir2);
    }
    const AABB *aabb = target->getCollisionEntity()->getAABB();
    int w = (aabb->dr.x - aabb->ul.x) / 2;
    int h = (aabb->dr.y - aabb->ul.y) / 2;
    bullet->setTrackingOffset(Vector2((rand() % w) - w / 2, (rand() % h) - h / 2));
    rad = so_atan2(target->getPosition().y + bullet->getTrackingOffset().y - bullet->getPosition().y, target->getPosition().x + bullet->getTrackingOffset().x - bullet->getPosition().x);
    if (bullet->getErrorAngle())
    {
        bullet->setFacing(part->getFacing() + rand() % (int)bullet->getErrorAngle() - (int)bullet->getErrorAngle() / 2);
    }
    else
    {
        bullet->setFacing(rad * 180 / PI);
    }
    bullet->updateTrackingPosition();
    bullets_list.push_back(bullet);
    return bullet;
}

void EntityManagement::createParts(Entity *entity, ym::Json *parts)
{
    if (entity == nullptr || entity->isExited())
    {
        return;
    }
    ym::Json::Array parts_arr = parts->getArray();
    for (auto it = parts_arr.begin(); it != parts_arr.end(); ++it)
    {
        ym::Json::Object part_obj = (*it)->getObject();
        std::string name = part_obj.at("name")->getString();
        int slot = part_obj.at("slot")->getInt();
        ym::Json *specific_part = data->getData(name.c_str());
        std::string type = specific_part->get("type")->getString();
        ym::Json *images = specific_part->get("images");
        std::string imagepath = images->get("imagepath")->getString();
        real scalewidth = images->get("scalewidth")->getDouble();
        real scaleHeight = images->get("scaleheight")->getDouble();
        std::string parttype = specific_part->get("parttype")->getString();
        Part *part = new Part();
        part->setImage(Resource::getInstance()->getImage(imagepath));
        part->animation = nullptr;
        part->setRenderSize(Vector2(scalewidth, scaleHeight));
        entity->setSlot(part, slot);
        ym::Json::Array actions = specific_part->get("actions")->getArray();
        for (auto it2 = actions.begin(); it2 != actions.end(); ++it2)
        {
            std::string action = (*it2)->getString();
            if (action.compare("attack") == 0)
            {
                part->actions += (int)PartAction::ATTACK;
                std::string attackType = specific_part->get("attackType")->getString();
                if (attackType.compare("instant") == 0)
                {
                    part->attackType = PartAttackType::INSTANT;
                    part->attackEffect = specific_part->get("attackeffect")->getString();
                    part->targetEffect = specific_part->get("targeteffect")->getString();
                }
                else if (attackType.compare("bullet") == 0)
                {
                    part->attackType = PartAttackType::BULLET;
                    ym::Json *bulletData = data->getData(specific_part->get("bullet")->getString().c_str());
                    Bullet *bullet = new Bullet();
                    bullet->setMinVelocity(bulletData->get("minvelocity")->getDouble());
                    bullet->setMaxVelocity(bulletData->get("maxvelocity")->getDouble());
                    bullet->setAcceleration(bulletData->get("acceleration")->getDouble());
                    bullet->setErrorAngle(bulletData->get("errorangle")->getDouble());
                    bullet->setAngleVelocity(bulletData->get("anglevelocity")->getDouble());
                    bullet->setAliveTime(bulletData->get("alivetime")->getDouble());
                    bullet->birthEffect = bulletData->get("birtheffect")->getString();
                    bullet->deathEffect = bulletData->get("deatheffect")->getString();
                    part->bulletOffset = Vector2(specific_part->get("bulletoffset")->getArray().at(0)->getDouble(), specific_part->get("bulletoffset")->getArray().at(1)->getDouble());
                    images = bulletData->get("images");
                    ym::Json::Array renderSize = images->get("rendersize")->getArray();
                    bullet->setRenderSize(Vector2(renderSize.at(0)->getDouble(), renderSize.at(1)->getDouble()));
                    bullet->setImage(resource->getInstance()->getImage(images->get("imagepath")->getString()));
                    ym::Json::Object collision = bulletData->get("collision")->getObject();
                    std::string shape = collision.at("shape")->getString();
                    // ((Animation *)ship->animation)->start();
                    if (shape.compare("circle") == 0)
                    {
                        CollisionEntityCircle *cir = new CollisionEntityCircle(collision.at("size")->getDouble(), bullet);
                        bullet->setCollisionEntity(cir);
                        // bullet->getCollisionEntity()->updatePosition(pos);
                        collisionManagement.add(bullet->getCollisionEntity());
                    }
                    part->bullet = bullet;

                    // bullets_list.push_back(bullet);
                }
                else
                {
                    part->attackType = PartAttackType::NONE;
                }
            }
            else if (action.compare("harvest") == 0)
            {
                part->actions += (int)PartAction::HARVEST;
            }
            else if (action.compare("move") == 0)
            {
                part->actions += (int)PartAction::MOVE;
            }
            else if (action.compare("gold") == 0)
            {
                part->actions += (int)PartAction::GOLD;
                part->gold = specific_part->get("gold")->getInt();
            }
        }
        if (parttype.compare("resource") == 0)
        {
            entity->isResource = true;
        }
        else
        {
            entity->isResource = false;
        }

        part->range = specific_part->get("range")->getDouble();
        part->attack = specific_part->get("attack")->getDouble();
        part->setAngleVelocity(specific_part->get("anglevelocity")->getDouble());

        part->attackCD = specific_part->get("attackcd")->getDouble();
        part->allowAttackFacingDifference = specific_part->get("allowattackfacingdifference")->getDouble();
        part->animation = createAnimation(data->getData(specific_part->get("animation")->getString().c_str()));
        part->followRange = specific_part->get("followrange")->getDouble();
        ((IAnimation *)part->animation)->start();
    }
}

IAnimation *EntityManagement::createAnimation(ym::Json *data)
{
    ym::Json *ani_josn = data;
    ym::Json *ani_frames = ani_josn->get("frames");
    ym::Json::Array array = ani_frames->getArray();
    ym::Json::Array renderSize = ani_josn->get("rendersize")->getArray();
    ym::Json::Array offset = ani_josn->get("offset")->getArray();
    IAnimation *ani = new IAnimation(Vector2(renderSize.at(0)->getInt(), renderSize.at(1)->getInt()), Vector2(offset.at(0)->getInt(), offset.at(1)->getInt()));
    std::string anchor = ani_josn->get("anchor")->getString();
    if (anchor.compare("left") == 0)
    {
        ani->setAnchor(Anchor::Left);
    }
    else if (anchor.compare("right") == 0)
    {
        ani->setAnchor(Anchor::Right);
    }
    else if (anchor.compare("top") == 0)
    {
        ani->setAnchor(Anchor::Top);
    }
    else if (anchor.compare("bottom") == 0)
    {
        ani->setAnchor(Anchor::Bottom);
    }
    else
    {
        ani->setAnchor(Anchor::Center);
    }
    for (auto it = array.begin(); it != array.end(); ++it)
    {
        ym::Json *frame = (*it);
        std::string imagename = frame->get(0)->getString();
        real interval = frame->get(1)->getDouble();
        ani->addFrame(Resource::getInstance()->getImage(imagename), interval);
    }
    return ani;
}

void EntityManagement::update(real delta)
{

    effectManagement.update(delta);
    // collisionManagement.updateQuadTree();
    collisionManagement.updateMesh();
    solveCollision(delta, collisionManagement.iteratorCount);
    for (auto it = selected_list.begin(); it != selected_list.end();)
    {
        Entity *entity = *it;
        if (!entity->isSelected)
        {
            it = selected_list.erase(it);
        }
        else
        {
            it++;
        }
    }
    for (auto it = hovers_list.begin(); it != hovers_list.end();)
    {
        Entity *entity = *it;
        if (entity->isExited() || !entity->hover)
        {
            it = hovers_list.erase(it);
        }
        else
        {
            it++;
        }
    }
    for (auto it = entities_list.begin(); it != entities_list.end();)
    {
        Entity *entity = *it;
        Ship *ship = (Ship *)*it;
        if (entity->isExited())
        {
            it = entities_list.erase(it);
            delete entity;
        }
        else
        {
            entity->update(delta);
            if (entity->harvestUnit != nullptr && entity->harvestUnit->orderType != (int)UnitOrderType::HARVEST)
            {
                entity->harvestUnit = nullptr;
            }
            for (int i = 0; i < sizeof(entity->slots) / sizeof(entity->slots[0]); ++i)
            {
                if (entity->slots[i].part != nullptr && entity->slots[i].part->animation != nullptr)
                {
                    ((IAnimation *)entity->slots[i].part->animation)->update(delta);
                }
            }
            if (ship->getHp() <= 0)
            {
                destroyEntity(ship);
            }

            it++;
        }
    }
    for (auto it = bullets_list.begin(); it != bullets_list.end();)
    {
        Bullet *bullet = *it;
        if (bullet->isExited())
        {
            it = bullets_list.erase(it);
            if (bullet->deathEffect.size() > 0)
            {
                effectManagement.createEffect(Data::getInstance()->getData(bullet->deathEffect.c_str()), bullet->getPosition(), bullet->getFacing(), 0);
            }
            delete bullet;
        }
        else
        {
            bullet->update(delta);
            Entity *entity = bullet->updateCollision(delta);
            if (entity && !entity->isExited())
            {
                Ship *ship = (Ship *)entity;
                ship->setHp(ship->getHp() - bullet->getAttack());
                destroyBullet(bullet);
            }
            it++;
        }
    }
    updateOrder(delta);
}

void EntityManagement::solveCollision(real delta, int count)
{
    if (count <= 0)
        return;
    collisionManagement.updateQuadTree();
    auto collisons = collisionManagement.updateCollisions();

    for (auto it = collisons->begin(); it != collisons->end(); ++it)
    {
        Collision *collison = *it;
        if ((*it)->a->getParent() == nullptr || (*it)->b->getParent() == nullptr)
        {
            continue;
        }
        Entity *a = (*it)->a->getParent();
        Entity *b = (*it)->b->getParent();
        Ship *ship_a = dynamic_cast<Ship *>((*it)->a->getParent());
        Ship *ship_b = dynamic_cast<Ship *>((*it)->b->getParent());
        if (a->isExited() || b->isExited())
        {
            continue;
        }
        bool astate = (int)a->orderType & (int)UnitOrderType::HARVEST || (int)a->orderType & (int)UnitOrderType::WITHDRAW;
        bool bstate = (int)b->orderType & (int)UnitOrderType::HARVEST || (int)b->orderType & (int)UnitOrderType::WITHDRAW;
        real factor = delta * collisionManagement.iteratorCount;

        if (a->getVelocity() == 0 && b->getVelocity() == 0)
        {
            a->setPosition(a->getPosition() - collison->direct * factor / 2);
        }
        if (a->getVelocity() == 0)
        {
            b->setPosition(b->getPosition() + collison->direct * factor);
        }
        else if (b->getVelocity() == 0)
        {
            a->setPosition(a->getPosition() - collison->direct * factor);
        }
        else if (!astate && !bstate)
        {
            if (ship_a->getOwnerID() != ship_b->getOwnerID())
            {
                if (a->orderType & (int)UnitOrderType::MOVE && b->orderType & (int)UnitOrderType::MOVE)
                {
                    a->setPosition(a->getPosition() - collison->direct * factor / 2);
                    b->setPosition(b->getPosition() + collison->direct * factor / 2);
                }
                else if (a->orderType & (int)UnitOrderType::MOVE)
                {
                    a->setPosition(a->getPosition() - collison->direct * factor);
                }
                else if (b->orderType & (int)UnitOrderType::MOVE)
                {
                    b->setPosition(b->getPosition() + collison->direct * factor);
                }
                else
                {
                    a->setPosition(a->getPosition() - collison->direct * factor / 2);
                    b->setPosition(b->getPosition() + collison->direct * factor / 2);
                }
            }
            else
            {
                a->setPosition(a->getPosition() - collison->direct * factor / 2);
                b->setPosition(b->getPosition() + collison->direct * factor / 2);
            }
        }
        a->getCollisionEntity()->updatePosition(a->getPosition());
        b->getCollisionEntity()->updatePosition(b->getPosition());
    }
    solveCollision(delta, --count);
}

void EntityManagement::updateOrder(real delta)
{
    for (auto it = orders_map.begin(); it != orders_map.end();)
    {
        bool done = false;
        std::queue<UnitOrder *> *que = it->second;
        if (que->empty())
        {
            ++it;
            continue;
        }
        UnitOrder *order = que->front();
        Entity *sender = order->sender;
        switch (order->type)
        {
        case UnitOrderType::MOVE:
        {
            sender->orderType = (int)UnitOrderType::MOVE;
            if (!order->data.pointOrder.path.empty())
            {
                Vector2 target = order->data.pointOrder.path.top();
                real angle = so_atan2(target.y - sender->getPosition().y, target.x - sender->getPosition().x) * 180 / PI;
                if (sender->move(delta, target))
                {
                    order->data.pointOrder.path.pop();
                }
            }
            else
            {
                order->data.pointOrder.path = collisionManagement.getNavmesh()->findPath(sender->getCollisionEntity(),order->data.pointOrder.pos);
                if (order->data.pointOrder.path.empty())
                {
                    real angle = so_atan2(order->data.pointOrder.pos.y - sender->getPosition().y, order->data.pointOrder.pos.x - sender->getPosition().x) * 180 / PI;
                    done = sender->move(delta, order->data.pointOrder.pos);
                }
            }
            for (int i = 0; i < 4; ++i)
            {
                if (sender->slots[i].part != nullptr && sender->slots[i].part->actions & (int)PartAction::MOVE)
                {
                    sender->slots[i].part->animation->setVisible(true);
                }
            }
            break;
        }
        case UnitOrderType::FOLLOW:
        {
            Entity *target = order->data.targetOrder.target;
            if (sender->approach(delta, target->getPosition(), followRange))
            {
                sender->orderType = (int)UnitOrderType::FOLLOW;
            }
            else
            {
                sender->orderType = (int)UnitOrderType::FOLLOW | (int)UnitOrderType::MOVE;
            }
            break;
        }
        case UnitOrderType::ATTACK:
        {
            Entity *target = order->data.targetOrder.target;
            if (target->isExited())
            {
                done = true;
                break;
            }
            real max = 0;
            for (int i = 0; i < sizeof(sender->slots) / sizeof(sender->slots[0]); ++i)
            {
                if (sender->slots[i].part != nullptr)
                {
                    if (sender->slots[i].part->actions & (int)PartAction::ATTACK)
                    {
                        max = so_max(max, sender->slots[i].part->range);
                        sender->slots[i].part->follow = order->data.targetOrder.target;
                    }
                }
            }
            CollisionEntityCircle *circle = dynamic_cast<CollisionEntityCircle *>(target->getCollisionEntity());
            if (circle != nullptr)
            {
                max += circle->getRadius();
            }
            real angle = so_atan2(target->getPosition().y - sender->getPosition().y, target->getPosition().x - sender->getPosition().x) * 180 / PI;
            if (sender->approach(delta, target->getPosition(), max))
            {
                sender->orderType = (int)UnitOrderType::ATTACK;
                for (int i = 0; i < sizeof(sender->slots) / sizeof(sender->slots[0]); ++i)
                {
                    if (sender->slots[i].part != nullptr)
                    {
                        real range = (sender->slots[i].part->range + circle->getRadius());
                        if (sender->slots[i].part->actions & (int)PartAction::ATTACK && (sender->getSlotPosition(i) - target->getPosition()).length2() <= range * range)
                        {
                            Part *p = sender->slots[i].part;
                            Vector2 pos = target->getPosition() - sender->getSlotPosition(i);
                            real angleDifference = so_anglediff(so_atan2(pos.y, pos.x) * 180 / PI, p->getFacing());
                            if (angleDifference <= p->allowAttackFacingDifference)
                            {
                                if (p->attackTimer.getElapsedDoubleSeconds() >= p->attackCD)
                                {
                                    if (p->attackType == PartAttackType::INSTANT)
                                    {
                                        ((Ship *)target)->hp -= p->attack;
                                        effectManagement.createEffect(data->getData(p->attackEffect.c_str()), (sender->getSlotPosition(i) + target->getPosition()) / 2, p->getFacing(), 0);
                                        effectManagement.createEffect(data->getData(p->targetEffect.c_str()), target->getPosition(), p->getFacing(), 0);
                                    }
                                    else if (p->attackType == PartAttackType::BULLET)
                                    {
                                        createBullet(&sender->slots[i], sender, target);
                                    }
                                    p->attackTimer.recordTimePoint();
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                sender->orderType = (int)UnitOrderType::MOVE | (int)UnitOrderType::ATTACK;
            }
            break;
        }
        case UnitOrderType::HARVEST:
        {
            Entity *harvest = order->data.harvestOrder.harvest;
            if (harvest == nullptr || harvest->isExited())
            {
                Entity *entity = findClosestFreeResource(ResourceType::GOLD, sender->getPosition(), 600);
                if (entity == nullptr)
                {
                    harvest = nullptr;
                    order->data.harvestOrder.harvest = harvest;
                }
                else
                {
                    harvest = entity;
                    order->data.harvestOrder.harvest = harvest;
                }
            }
            Ship *ship = (Ship *)sender;
            real min = 999999;
            Part *p = nullptr;
            real require = ship->capacity - ship->carry;
            if (harvest == nullptr && ship->carry <= 0)
            {
                done = true;
                break;
            }
            if (require == 0 || (harvest == nullptr && ship->carry > 0))
            {
                Entity *withdraw = order->data.harvestOrder.withdraw;
                if (withdraw == nullptr || withdraw->isExited())
                {
                    Entity *base = findClosestBase(ship->getOwnerID(), sender->getPosition());
                    if (base == nullptr)
                    {
                        done = true;
                        break;
                    }
                    else
                    {
                        withdraw = base;
                        order->data.harvestOrder.withdraw = withdraw;
                    }
                }
                CollisionEntityCircle *circle = dynamic_cast<CollisionEntityCircle *>(withdraw->getCollisionEntity());
                CollisionEntityCircle *circle2 = dynamic_cast<CollisionEntityCircle *>(sender->getCollisionEntity());
                min = 0;
                if (circle != nullptr && circle2 != nullptr)
                {
                    min += circle->getRadius();
                    min += circle2->getRadius();
                }
                sender->orderType = (int)UnitOrderType::WITHDRAW | (int)UnitOrderType::MOVE;
                if (sender->approach(delta, withdraw->getPosition(), min))
                {
                    Static::golds[ship->getOwnerID()] += ship->carry;
                    ship->carry = 0;
                }
                break;
            }
            else
            {
                sender->orderType = (int)UnitOrderType::HARVEST | (int)UnitOrderType::MOVE;
            }
            for (int i = 0; i < sizeof(sender->slots) / sizeof(sender->slots[0]); ++i)
            {
                if (sender->slots[i].part != nullptr)
                {
                    if (sender->slots[i].part->actions & (int)PartAction::HARVEST)
                    {

                        min = so_min(min, sender->slots[i].part->range);
                        p = sender->slots[i].part;
                        p->follow = order->data.targetOrder.target;
                    }
                }
            }
            require = so_min(require, p->attack);
            CollisionEntityCircle *circle = dynamic_cast<CollisionEntityCircle *>(harvest->getCollisionEntity());
            CollisionEntityCircle *circle2 = dynamic_cast<CollisionEntityCircle *>(sender->getCollisionEntity());
            if (circle != nullptr && circle2 != nullptr)
            {
                min += circle->getRadius();
            }
            real angle = so_atan2(harvest->getPosition().y - sender->getPosition().y, harvest->getPosition().x - sender->getPosition().x) * 180 / PI;
            if (sender->approach(delta, harvest->getPosition(), min))
            {
                if (harvest->harvestUnit != nullptr && harvest->harvestUnit != sender)
                {
                    Entity *entity = findClosestFreeResource(ResourceType::GOLD, sender->getPosition(), 600);
                    if (entity != nullptr)
                    {
                        order->data.harvestOrder.harvest = entity;
                    }
                    break;
                }
                else
                {
                    harvest->harvestUnit = sender;
                    sender->orderType = (int)UnitOrderType::HARVEST;
                }
                if (p->rotateTo(delta, angle) <= p->allowAttackFacingDifference)
                {
                    if (p->attackTimer.getElapsedDoubleSeconds() >= p->attackCD)
                    {
                        real real_carry = 0;
                        int i = 0;

                        if (p->attackType == PartAttackType::INSTANT)
                        {
                            effectManagement.createEffect(data->getData(p->attackEffect.c_str()), (sender->getPosition() + harvest->getPosition()) / 2, p->getFacing(), 0);
                            effectManagement.createEffect(data->getData(p->targetEffect.c_str()), harvest->getPosition(), p->getFacing(), 0);
                            for (; real_carry < require && i < 4; ++i)
                            {
                                if (harvest->slots[i].part == nullptr || harvest->slots[i].part->gold <= 0)
                                {
                                    continue;
                                }
                                if (harvest->slots[i].part->gold > require)
                                {
                                    harvest->slots[i].part->gold -= require;
                                    real_carry += require;
                                    break;
                                }
                                else
                                {
                                    real_carry += harvest->slots[i].part->gold;
                                    harvest->slots[i].part->gold = 0;
                                    delete harvest->slots[i].part;
                                    harvest->slots[i].part = nullptr;
                                }
                            }

                            // effectManagement.creatEffect(data->getData("eff_mininglaser"), (sender->getPosition() + harvest->getPosition()) / 2, p->getFacing(), 0.2);

                            if (i >= 4)
                            {
                                p->follow = nullptr;
                                destroyEntity(harvest);
                            }
                            ship->carry += real_carry;
                            p->attackTimer.recordTimePoint();
                        }
                    }
                }
                sender->accelerating = false;
                sender->decelerating = true;
            }
            break;
        }
        case UnitOrderType::WITHDRAW:
        {
            Ship *ship = (Ship *)sender;
            Entity *target = order->data.targetOrder.target;
            if (target == nullptr || target->isExited())
            {
                done = true;
                break;
            }
            if (ship->carry < 0)
            {
                done = true;
                break;
            }
            real min = 0;
            CollisionEntityCircle *circle = dynamic_cast<CollisionEntityCircle *>(target->getCollisionEntity());
            CollisionEntityCircle *circle2 = dynamic_cast<CollisionEntityCircle *>(sender->getCollisionEntity());
            min = 0;
            if (circle != nullptr && circle2 != nullptr)
            {
                min += circle->getRadius();
                min += circle2->getRadius();
            }
            if (sender->approach(delta, target->getPosition(), min))
            {
                done = true;
                Static::golds[ship->getOwnerID()] += ship->carry;
                ship->carry = 0;
            }
            else
            {
                sender->orderType = (int)UnitOrderType::WITHDRAW | (int)UnitOrderType::MOVE;
            }
            break;
        }
        default:
            break;
        }
        if (done)
        {
            delete order;
            que->pop();
            if (que->empty())
            {
                sender->accelerating = false;
                sender->decelerating = true;
                sender->orderType = (int)UnitOrderType::STOP;
            }
        }
        else
        {
            ++it;
        }
    }
    // SDL_Log("Order size:%d", orders_map.size());
}

void EntityManagement::click(int x, int y, int mask)
{
    Ship *ship = (Ship *)hoverEntity(x, y);
    if (ship == nullptr)
    {
        return;
    }
    if (mask & (1 << 2))
    {
        if (selectedOwnerID == ship->getOwnerID())
        {
            ship->isSelected = !ship->isSelected;
            if (ship->isSelected)
            {
                selected_list.push_back(ship);
            }
        }
    }
    else
    {
        for (auto it = selected_list.begin(); it != selected_list.end();)
        {
            (*it)->isSelected = false;
            it = selected_list.erase(it);
        }
        selectedOwnerID = ship->getOwnerID();
        selected_list.push_back(ship);
        ship->isSelected = true;
    }
    // SDL_Log("click");
}

void EntityManagement::rightClick(int x, int y, int mask)
{
    // if (selectedOwnerID != Static::playerID)
    // {
    //     return;
    // }
    Ship *hover = (Ship *)hoverEntity(x, y);
    bool shift = (mask & (1 << 2));
    std::vector<Entity *> move_list;
    if (!selected_list.empty())
    {
        for (auto entity : selected_list)
        {
            Ship *ship = (Ship *)entity;
            int action = 0;
            for (int i = 0; i < 4; i++)
            {
                if (ship->slots[i].part == nullptr)
                {
                    continue;
                }
                action |= ship->slots[i].part->actions;
            }
            if (hover != nullptr && hover != entity)
            {
                if (hover->isResource && action & PartAction::HARVEST)
                {
                    UnitOrder *order = new UnitOrder();
                    order->type = UnitOrderType::HARVEST;
                    order->data.harvestOrder.harvest = hover;
                    order->data.harvestOrder.withdraw = nullptr;
                    order->sender = entity;
                    sendOrder(order, shift);
                    continue;
                }
                if (hover->getOwnerID() != 13 && hover->getOwnerID() != ship->getOwnerID() && action & PartAction::ATTACK)
                {
                    UnitOrder *order = new UnitOrder();
                    order->sender = entity;
                    order->type = UnitOrderType::ATTACK;
                    order->data.targetOrder.target = hover;
                    sendOrder(order, shift);
                    for (int i = 0; i < sizeof(order->sender->slots) / sizeof(order->sender->slots[0]); ++i)
                    {
                        if (order->sender->slots[i].part != nullptr)
                        {
                            order->sender->slots[i].part->follow = order->data.targetOrder.target;
                        }
                    }
                }
                else if (hover->isBase && ship->carry > 0 && action & PartAction::MOVE && action & PartAction::HARVEST)
                {
                    UnitOrder *order = new UnitOrder();
                    order->sender = entity;
                    order->type = UnitOrderType::WITHDRAW;
                    order->data.targetOrder.target = hover;
                    sendOrder(order, shift);
                }
                else if (action & PartAction::MOVE)
                {
                    // SDL_Log("Follow start");
                    UnitOrder *order = new UnitOrder();
                    order->sender = entity;
                    order->type = UnitOrderType::FOLLOW;
                    order->data.targetOrder.target = hover;
                    sendOrder(order, shift);
                }
            }
            else
            {
                if (action & PartAction::MOVE)
                {
                    move_list.push_back(entity);
                }
            }
        }
    }
    if (move_list.empty())
    {
        return;
    }
    Vector2 center;
    for (auto it = move_list.begin(); it != move_list.end(); ++it)
    {
        center += (*it)->getPosition();
    }
    center = center / move_list.size();
    real min = 0;
    int min_index = 0;
    Vector2 target_pos(x, y);
    real temp;
    Entity *p;
    for (int i = 0; i < move_list.size(); i++)
    {
        min = (move_list[0]->getPosition() - target_pos).length2();
        min_index = i;
        for (int j = i + 1; j < move_list.size(); j++)
        {
            temp = (move_list[j]->getPosition() - target_pos).length2();
            if (temp < min)
            {
                min_index = j;
                min = temp;
            }
            p = move_list[i];
            move_list[i] = move_list[min_index];
            move_list[min_index] = p;
        }
    }
    int layer = 0;
    int layer_count[4] = {1, 6, 12, 18};
    int count = 0;

    int m[25][2] = {
        {0, 0},
        {-1, -1},
        {0, -1},
        {1, -1},
        {-1, 0},
        {1, 0},
        {-1, 1},
        {0, 1},
        {1, 1},
        {-1, -2},
        {0, -2},
        {1, -2},
        {2, -2},
        {2, -1},
        {2, 0},
        {2, 1},
        {2, 2},
        {1, 2},
        {0, 2},
        {-1, 2},
        {-2, 2},
        {-2, 1},
        {-2, 0},
        {-2, -1},
        {-2, -2}

    };
    for (auto it = move_list.begin(); it != move_list.end(); ++it)
    {
        Entity *entity = *it;
        UnitOrder *order = new UnitOrder();
        order->sender = entity;
        order->type = UnitOrderType::MOVE;
        Vector2 dv;
        if (count >= 25)
        {
            int l = (int)so_sqrt(count);
            dv = Vector2(rand() % l - l / 2, rand() % l - l / 2);
        }
        else
        {
            dv = Vector2(m[count][0], m[count][1]);
        }
        CollisionEntityCircle *circle = dynamic_cast<CollisionEntityCircle *>(entity->getCollisionEntity());
        if (circle != nullptr)
        {
            order->data.pointOrder.pos = Vector2(x, y) + dv * circle->getRadius() * 2;
        }

        sendOrder(order, shift);
        count++;
    }
    effectManagement.createEffect(Data::getInstance()->getData("eff_pointorder"), Vector2(x, y), 0, 0);
}

void EntityManagement::boxSelect(const SDL_Rect *rc, int mask)
{
    if (!(mask & (1 << 2)))
    {
        std::vector<Ship *> temp;
        for (auto it = entities_list.begin(); it != entities_list.end(); ++it)
        {
            Ship *ship = (Ship *)*it;
            if (ship->getOwnerID() == Static::playerID && ship->getPosition().x > rc->x && ship->getPosition().y > rc->y && ship->getPosition().x <= rc->x + rc->w && ship->getPosition().y <= rc->y + rc->h)
            {
                temp.push_back(ship);
            }
        }
        if (!temp.empty())
        {
            for (auto it = selected_list.begin(); it != selected_list.end();)
            {
                (*it)->isSelected = false;
                it = selected_list.erase(it);
            }
            for (auto it = temp.begin(); it != temp.end(); ++it)
            {
                selected_list.push_back(*it);
                selectedOwnerID = (*it)->getOwnerID();
                (*it)->isSelected = true;
            }
        }
    }
    else
    {
        for (auto it = entities_list.begin(); it != entities_list.end(); ++it)
        {
            Ship *ship = (Ship *)*it;
            if (ship->getOwnerID() == selectedOwnerID && ship->getPosition().x > rc->x && ship->getPosition().y > rc->y && ship->getPosition().x <= rc->x + rc->w && ship->getPosition().y <= rc->y + rc->h)
            {
                if (ship->isSelected)
                {
                    ship->isSelected = false;
                }
                else
                {
                    selected_list.push_back(ship);
                    ship->isSelected = true;
                }
            }
        }
    }
}

void EntityManagement::mouseMotion(int x, int y, int mask)
{
    Entity *hover = hoverEntity(x, y);
    for (auto it = hovers_list.begin(); it != hovers_list.end();)
    {
        (*it)->hover = false;
        it = hovers_list.erase(it);
    }
    if (hover != nullptr)
    {
        hovers_list.push_back(hover);
        hover->hover = true;
    }
}

Entity *EntityManagement::hoverEntity(int x, int y)
{
    for (auto it = entities_list.begin(); it != entities_list.end(); ++it)
    {
        Entity *entity = *it;
        if (distance(x - entity->getPosition().x, y - entity->getPosition().y) <= entity->selectedRange)
        {
            return entity;
        }
    }
    return nullptr;
}

void EntityManagement::sendOrder(UnitOrder *unitOrder, bool shift)
{
    if (unitOrder == nullptr)
    {
        return;
    }
    if (orders_map[unitOrder->sender] == nullptr)
    {
        orders_map[unitOrder->sender] = new std::queue<UnitOrder *>();
    }
    std::queue<UnitOrder *> *que = orders_map[unitOrder->sender];
    if (!shift)
    {
        while (!que->empty())
        {
            UnitOrder *order = que->front();
            que->pop();
            delete order;
        }
    }
    if (que->size() >= 10)
    {
        delete unitOrder;
    }
    else
    {
        que->push(unitOrder);
    }
}

const std::vector<Entity *> *EntityManagement::getEntities()
{
    return &entities_list;
}

const std::vector<Entity *> *EntityManagement::getSelected()
{
    return &selected_list;
}

const std::vector<Entity *> *EntityManagement::getHover()
{
    return &hovers_list;
}

const std::queue<UnitOrder *> *EntityManagement::getUnitOrders(Entity *entity)
{
    if (entity == nullptr)
    {
        return nullptr;
    }
    auto it = orders_map.find(entity);
    return it != orders_map.end() ? it->second : nullptr;
}

UnitOrder *EntityManagement::getTopOrder(Entity *entity)
{
    auto it = orders_map.find(entity);
    if (it == orders_map.end())
    {
        return nullptr;
    }
    auto que = it->second;
    return que->empty() ? nullptr : que->front();
}

const std::list<Collision *> *EntityManagement::getCollisions()
{
    return collisionManagement.getCollisions();
}

QuadTree *EntityManagement::getQuadTree() const
{
    return collisionManagement.getQuadTree();
}

void EntityManagement::freeQuadTree()
{
    collisionManagement.freeQuadTree();
}

const std::vector<Effect *> *EntityManagement::getEffects()
{
    return effectManagement.getEffects();
}

const std::vector<Bullet *> *EntityManagement::getBullets()
{
    return &bullets_list;
}

void EntityManagement::unitStop(Entity *entity)
{
    auto it = orders_map.find(entity);
    entity->orderType = (int)UnitOrderType::STOP;
    if (it == orders_map.end())
    {
        return;
    }
    auto que = it->second;
    if (que == nullptr || que->empty())
    {
        return;
    }
    while (!que->empty())
    {
        UnitOrder *order = que->front();
        delete order;
        que->pop();
    }
}

const std::list<Entity *> EntityManagement::findBases(int playerID) const
{
    std::list<Entity *> list;
    for (auto it = entities_list.begin(); it < entities_list.end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        if (ship->getOwnerID() == playerID && ship->isBase)
        {
            list.push_back(*it);
        }
    }
    return list;
}

const std::list<Entity *> EntityManagement::findResources(ResourceType res) const
{
    std::list<Entity *> list;
    for (auto it = entities_list.begin(); it < entities_list.end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        for (int i = 0; i < 4; i++)
        {
            if (ship->slots[i].part == nullptr)
            {
                continue;
            }
            if (ship->slots[i].part->gold > 0)
            {
                list.push_back(*it);
                continue;
            }
        }
    }
    return list;
}

const std::list<Entity *> EntityManagement::findFreeResources(ResourceType res) const
{
    std::list<Entity *> list;
    for (auto it = entities_list.begin(); it < entities_list.end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        if (ship->harvestUnit != nullptr)
        {
            continue;
        }
        for (int i = 0; i < 4; i++)
        {
            if (ship->slots[i].part == nullptr)
            {
                continue;
            }
            if (ship->slots[i].part->gold > 0)
            {
                list.push_back(*it);
                continue;
            }
        }
    }
    return list;
}

Entity *EntityManagement::findClosestFreeResource(ResourceType res, Vector2 pos, real range) const
{
    auto list = findFreeResources(res);
    Entity *closest = nullptr;
    real min = range * range;
    for (auto it = list.begin(); it != list.end(); ++it)
    {
        Entity *entity = *it;
        real temp = (entity->getPosition() - pos).length2();
        if (temp > range * range)
        {
            continue;
        }
        if (temp < min)
        {
            min = temp;
            closest = entity;
        }
    }
    return closest;
}

Entity *EntityManagement::findClosestBase(int playerID, Vector2 pos, real range) const
{
    auto list = findBases(playerID);
    Entity *closest = nullptr;
    real min = 500000;
    for (auto it = list.begin(); it != list.end(); ++it)
    {
        Entity *entity = *it;
        real temp = (entity->getPosition() - pos).length2();
        if (range > 0 && temp > range * range)
        {
            continue;
        }
        if (temp < min)
        {
            min = temp;
            closest = entity;
        }
    }
    return closest;
}

const std::list<CollisionEntity *> *EntityManagement::getCollisionEntities() const
{
    return collisionManagement.getCollisionEntities();
}

const Mesh2D *EntityManagement::getMesh() const
{
    return collisionManagement.getMesh();
}

Navmesh *EntityManagement::getNavmesh()
{
    return collisionManagement.getNavmesh();
}

const std::vector<Edge *> *EntityManagement::getEdge() const
{
    return collisionManagement.getEdge();
}
